﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TGIApp.Model;
using TGIApp.Data;
using TGIApp.Data.EntityFramework;


namespace TGIApp.Business
{
    public class TgiService : ITgiService
    {
        private IRepository repository;
        public TgiService()
        {
        }

        #region User

        #region Client
        public List<User> GetAllClients()
        {
            repository = new GenericRepository();
            var clients = repository.Find<User>(Specifications.ClientSpecification).ToList();
            return clients;
        }

        public User GetClientById(int id)
        {
            repository = new GenericRepository();
            var client = repository.GetAll<User>("Address, Address.City").Where(user => user.Id == id).FirstOrDefault();
            return client;
        }

        public void CreateClient(User user)
        {
            repository = new GenericRepository();
            try
            {
                repository.UnitOfWork.BeginTransaction();
                user.UserType = (short)UserType.Client;
                user.Role_Id = (int)UserType.Client;
                user.Address.City = null;
                repository.Add(user.Address);
                repository.Add<User>(user);
                repository.UnitOfWork.CommitTransaction();
            }
            catch (Exception)
            {
                if (repository.UnitOfWork.IsInTransaction)
                    repository.UnitOfWork.RollBackTransaction();
                throw;
            }

        }

        public void UpdateClient(User user)
        {
            repository = new GenericRepository();
            try
            {
                repository.UnitOfWork.BeginTransaction();
                user.UserType = (short)UserType.Client;
                user.Role_Id = (int)UserType.Client;
                repository.Update<Address>(user.Address);
                repository.Update<User>(user);
                repository.UnitOfWork.CommitTransaction();
            }
            catch (Exception)
            {
                if (repository.UnitOfWork.IsInTransaction)
                    repository.UnitOfWork.RollBackTransaction();
                throw;
            }
        }
        //TODO:Delete related  objects first like Events or stop user to delete 
        public void DeleteClient(User user)
        {
            repository = new GenericRepository();
            try
            {
                repository.UnitOfWork.BeginTransaction();
                repository.Attach<User>(user);
                repository.Attach<Address>(user.Address);
                repository.Delete<User>(user);
                repository.Delete<Address>(user.Address);
                repository.UnitOfWork.CommitTransaction();
            }
            catch (Exception)
            {
                if (repository.UnitOfWork.IsInTransaction)
                    repository.UnitOfWork.RollBackTransaction();
                throw;
            }
        }

        //TODO:Delete related  objects first like Events or stop user to delete 
        public void DeleteClientById(int id)
        {
            repository = new GenericRepository();
            try
            {
                repository.UnitOfWork.BeginTransaction();
                User user = repository.GetByKey<User>(id);
                repository.Delete<User>(u => u.Id == id);
                repository.Delete<Address>(u => u.Id == user.Address_Id);
                repository.UnitOfWork.CommitTransaction();
            }
            catch (Exception)
            {
                if (repository.UnitOfWork.IsInTransaction)
                    repository.UnitOfWork.RollBackTransaction();
                throw;
            }
        }

        #endregion

        #region Agent
        public List<User> GetAllAgents()
        {
            repository = new GenericRepository();
           // var agents = repository.GetAll<User>().Where(user => user.UserType == 3).ToList();
            var agents = repository.Find(Specifications.AgentSpecification).ToList();
            return agents;
        }

        public User GetAgentById(int id)
        {
            repository = new GenericRepository();
            var agent = repository.GetAll<User>("Address, Address.City").Where(user => user.Id == id).FirstOrDefault();
            return agent;
        }

        public void CreateAgent(User user)
        {
            repository = new GenericRepository();
            try
            {
                repository.UnitOfWork.BeginTransaction();
                user.UserType = (short)UserType.Agent;
                user.Role_Id = (int)UserType.Agent;
                user.Address.City = null;
                var agentBranch = new AgentBranch() { Name = user.UserName, Address = user.Address, User = user };
                repository.Add(user.Address);
                repository.Add<User>(user);
                repository.Add<AgentBranch>(agentBranch);
                repository.UnitOfWork.CommitTransaction();
            }
            catch (Exception)
            {
                if (repository.UnitOfWork.IsInTransaction)
                    repository.UnitOfWork.RollBackTransaction();
                throw;
            }

        }

        public void UpdateAgent(User user)
        {
            repository = new GenericRepository();
            try
            {
                repository.UnitOfWork.BeginTransaction();
                user.UserType = (short)UserType.Agent;
                user.Role_Id = (int)UserType.Agent;
                user.Address.City = null;
                var agentBranch = repository.GetAll<AgentBranch>().Where(branch => branch.Agent_Id == user.Id).FirstOrDefault();
                agentBranch.Name = user.UserName;
                repository.Update<AgentBranch>(agentBranch);
                repository.Update<Address>(user.Address);
                repository.Update<User>(user);
                repository.UnitOfWork.CommitTransaction();
            }
            catch (Exception)
            {
                if (repository.UnitOfWork.IsInTransaction)
                    repository.UnitOfWork.RollBackTransaction();
                throw;
            }
        }
        //TODO: Delete related objects first like AgentBranches
        public void DeleteAgent(User user)
        {
            repository = new GenericRepository();
            try
            {
                repository.UnitOfWork.BeginTransaction();
                repository.Delete<AgentBranch>(branch => branch.Agent_Id == user.Id);
                repository.Attach<User>(user);
                repository.Attach<Address>(user.Address);
                repository.Delete<User>(user);
                repository.Delete<Address>(user.Address);
                repository.UnitOfWork.CommitTransaction();
            }
            catch (Exception)
            {
                if (repository.UnitOfWork.IsInTransaction)
                    repository.UnitOfWork.RollBackTransaction();
                throw;
            }
        }
        //TODO: Delete related objects first like AgentBranches
        public void DeleteAgentById(int id)
        {
            repository = new GenericRepository();
            try
            {
                repository.UnitOfWork.BeginTransaction();
                User user = repository.GetByKey<User>(id);
                repository.Delete<AgentBranch>(branch => branch.Agent_Id == id);
                repository.Delete<User>(u => u.Id == id);
                repository.Delete<Address>(u => u.Id == user.Address_Id);
                repository.UnitOfWork.CommitTransaction();
            }
            catch (Exception)
            {
                if (repository.UnitOfWork.IsInTransaction)
                    repository.UnitOfWork.RollBackTransaction();
                throw;
            }
        }

        #endregion

        #region Customer
        public List<User> GetAllCustomers()
        {
            repository = new GenericRepository();
            var customers = repository.Find<User>(Specifications.CustomerSpecification).ToList();
            return customers;
        }

        public User GetCustomerById(int id)
        {
            repository = new GenericRepository();
            var customer = repository.GetAll<User>("Address, Address.City").Where(user => user.Id == id).FirstOrDefault();
            return customer;
        }

        public void CreateCustomer(User user)
        {
            repository = new GenericRepository();
            try
            {
                repository.UnitOfWork.BeginTransaction();
                user.UserType = (short)UserType.Customer;
                user.Role_Id = (int)UserType.Customer;
                user.Address.City = null;
                repository.Add(user.Address);
                repository.Add<User>(user);
                repository.UnitOfWork.CommitTransaction();
            }
            catch (Exception)
            {
                if (repository.UnitOfWork.IsInTransaction)
                    repository.UnitOfWork.RollBackTransaction();
                throw;
            }

        }

        public void UpdateCustomer(User user)
        {
            repository = new GenericRepository();
            try
            {
                repository.UnitOfWork.BeginTransaction();
                user.UserType = (short)UserType.Customer;
                user.Role_Id = (int)UserType.Customer;
                user.Address.City = null;
                repository.Update<Address>(user.Address);
                repository.Update<User>(user);
                repository.UnitOfWork.CommitTransaction();
            }
            catch (Exception)
            {
                if (repository.UnitOfWork.IsInTransaction)
                    repository.UnitOfWork.RollBackTransaction();
                throw;
            }
        }
        //TODO: delete related objects first
        public void DeleteCustomer(User user)
        {
            repository = new GenericRepository();
            try
            {
                repository.UnitOfWork.BeginTransaction();
                repository.Attach<User>(user);
                repository.Attach<Address>(user.Address);
                repository.Delete<User>(user);
                repository.Delete<Address>(user.Address);
                repository.UnitOfWork.CommitTransaction();
            }
            catch (Exception)
            {
                if (repository.UnitOfWork.IsInTransaction)
                    repository.UnitOfWork.RollBackTransaction();
                throw;
            }
        }
        //TODO: delete related objects first
        public void DeleteCustomerById(int id)
        {
            repository = new GenericRepository();
            try
            {
                repository.UnitOfWork.BeginTransaction();
                User user = repository.GetByKey<User>(id);
                repository.Delete<User>(u => u.Id == id);
                repository.Delete<Address>(u => u.Id == user.Address_Id);
                repository.UnitOfWork.CommitTransaction();
            }
            catch (Exception)
            {
                if (repository.UnitOfWork.IsInTransaction)
                    repository.UnitOfWork.RollBackTransaction();
                throw;
            }
        }
        #endregion

        #endregion

        #region AgentBranches
        public List<AgentBranch> GetAllAgentBranches()
        {
            repository = new GenericRepository();
            var agentBranches = repository.GetAll<AgentBranch>().ToList();
            return agentBranches;
        }

        public AgentBranch GetAgentBranchById(int id)
        {
            throw new NotImplementedException();
        }

        public void CreateAgentBranch(AgentBranch agentBranch)
        {
            throw new NotImplementedException();
        }

        public void UpdateAgentBranch(AgentBranch agentBranch)
        {
            throw new NotImplementedException();
        }

        public void DeleteAgentBranch(AgentBranch agentBranch)
        {
            throw new NotImplementedException();
        }

        public void DeleteAgentBranchById(int id)
        {
            throw new NotImplementedException();
        }

        #endregion

        #region Roles
        public List<string> GetRolesForUser(string userName)
        {
            var providerHelper = new ProviderHelper();
            return providerHelper.GetRolesForUser(userName);
        }
        public List<Role> GetAllRoles()
        {
            repository = new GenericRepository();
            var roles = repository.GetAll<Role>().ToList();
            return roles;
        }
        public void CreateRole(Role role)
        {
            repository = new GenericRepository();
            try
            {
                repository.UnitOfWork.BeginTransaction();
                repository.Add<Role>(role);
                repository.UnitOfWork.CommitTransaction();
            }
            catch (Exception)
            {
                if (repository.UnitOfWork.IsInTransaction)
                    repository.UnitOfWork.RollBackTransaction();
                throw;
            }
        }

        public Role GetRoleById(int id)
        {
            repository = new GenericRepository();
            var role = repository.GetByKey<Role>(id);
            return role;
        }

        public void UpdateRole(Role role)
        {
            repository = new GenericRepository();
            try
            {
                repository.UnitOfWork.BeginTransaction();
                repository.Update<Role>(role);
                repository.UnitOfWork.CommitTransaction();
            }
            catch (Exception)
            {
                if (repository.UnitOfWork.IsInTransaction)
                    repository.UnitOfWork.RollBackTransaction();
                throw;
            }
        }

        public void DeleteRole(Role role)
        {
            repository = new GenericRepository();
            try
            {
                repository.UnitOfWork.BeginTransaction();
                repository.Attach<Role>(role);
                repository.Delete<Role>(role);
                repository.UnitOfWork.CommitTransaction();
            }
            catch (Exception)
            {
                if (repository.UnitOfWork.IsInTransaction)
                    repository.UnitOfWork.RollBackTransaction();
                throw;
            }
        }

        public void DeleteRoleById(int id)
        {
            repository = new GenericRepository();
            try
            {
                repository.UnitOfWork.BeginTransaction();
                repository.Delete<Role>(u => u.Id == id);
                repository.UnitOfWork.CommitTransaction();
            }
            catch (Exception)
            {
                if (repository.UnitOfWork.IsInTransaction)
                    repository.UnitOfWork.RollBackTransaction();
                throw;
            }
        }

        #endregion

        #region Events
        public List<Event> GetAllEvents()
        {
            repository = new GenericRepository();
            var events = repository.GetAll<Event>().ToList();
            return events;
        }

        public void CreateEvent(Event evnt)
        {
            repository = new GenericRepository();
            try
            {
                repository.UnitOfWork.BeginTransaction();
                repository.Add<Event>(evnt);
                repository.UnitOfWork.CommitTransaction();
            }
            catch (Exception)
            {
                if (repository.UnitOfWork.IsInTransaction)
                    repository.UnitOfWork.RollBackTransaction();
                throw;
            }
        }

        public void UpdateEvent(Event evnt)
        {
            repository = new GenericRepository();
            try
            {
                repository.UnitOfWork.BeginTransaction();
                repository.Update<Event>(evnt);
                repository.UnitOfWork.CommitTransaction();
            }
            catch (Exception)
            {
                if (repository.UnitOfWork.IsInTransaction)
                    repository.UnitOfWork.RollBackTransaction();
                throw;
            }
        }

        public void DeleteEvent(Event evnt)
        {
            repository = new GenericRepository();
            try
            {
                repository.UnitOfWork.BeginTransaction();
                repository.Attach<Event>(evnt);
                repository.Delete<Event>(evnt);
                repository.UnitOfWork.CommitTransaction();
            }
            catch (Exception)
            {
                if (repository.UnitOfWork.IsInTransaction)
                    repository.UnitOfWork.RollBackTransaction();
                throw;
            }
        }

        public void DeleteEventById(int id)
        {
            repository = new GenericRepository();
            try
            {
                repository.UnitOfWork.BeginTransaction();
                repository.Delete<Event>(u => u.Id == id);
                repository.UnitOfWork.CommitTransaction();
            }
            catch (Exception)
            {
                if (repository.UnitOfWork.IsInTransaction)
                    repository.UnitOfWork.RollBackTransaction();
                throw;
            }
        }

        public Event GetEventById(int id)
        {
            repository = new GenericRepository();
            var evnt = repository.GetByKey<Event>(id);
            return evnt;
        }

        #endregion

        #region Venue
        public List<Venue> GetAllVenues()
        {
            repository = new GenericRepository();
            var venues = repository.GetAll<Venue>().ToList();
            return venues;
        }

        public Venue GetVenueById(int id)
        {
            repository = new GenericRepository();
            var venue = repository.GetAll<Venue>("Address,Address.City,Contact").Where(v => v.Id == id).FirstOrDefault();
            return venue;
        }

        public void CreateVenue(Venue venue)
        {
            repository = new GenericRepository();
            try
            {
                repository.UnitOfWork.BeginTransaction();
                venue.Address.City = null;
                repository.Add(venue.Address);
                repository.Add(venue.Contact);
                repository.Add<Venue>(venue);
                repository.UnitOfWork.CommitTransaction();
            }
            catch (Exception)
            {
                if (repository.UnitOfWork.IsInTransaction)
                    repository.UnitOfWork.RollBackTransaction();
                throw;
            }
        }

        public void UpdateVenue(Venue venue)
        {
            repository = new GenericRepository();
            try
            {
                repository.UnitOfWork.BeginTransaction();

                repository.Update<Address>(venue.Address);
                repository.Update<Contact>(venue.Contact);
                repository.Update<Venue>(venue);
                repository.UnitOfWork.CommitTransaction();
            }
            catch (Exception)
            {
                if (repository.UnitOfWork.IsInTransaction)
                    repository.UnitOfWork.RollBackTransaction();
                throw;
            }
        }

        public void DeleteVenue(Venue venue)
        {
            repository = new GenericRepository();
            try
            {
                repository.UnitOfWork.BeginTransaction();
                repository.Attach<Venue>(venue);
                repository.Attach<Address>(venue.Address);
                repository.Attach<Contact>(venue.Contact);
                repository.Delete<Venue>(venue);
                repository.Delete<Address>(venue.Address);
                repository.Delete<Contact>(venue.Contact);
                repository.UnitOfWork.CommitTransaction();
            }
            catch (Exception)
            {
                if (repository.UnitOfWork.IsInTransaction)
                    repository.UnitOfWork.RollBackTransaction();
                throw;
            }
        }

        public void DeleteVenueById(int id)
        {
            repository = new GenericRepository();
            try
            {
                repository.UnitOfWork.BeginTransaction();
                var venue = repository.GetByKey<Venue>(id);
                repository.Delete<Venue>(u => u.Id == id);
                repository.Delete<Address>(u => u.Id == venue.Address_Id);
                repository.Delete<Contact>(u => u.Id == venue.Contacts_Id);
                repository.UnitOfWork.CommitTransaction();
            }
            catch (Exception)
            {
                if (repository.UnitOfWork.IsInTransaction)
                    repository.UnitOfWork.RollBackTransaction();
                throw;
            }
        }

        #endregion

        #region EventVenue(Shows)
        public List<EventVenue> GetAllEventVenues()
        {
            repository = new GenericRepository();
            //var eventVenues = repository.GetAll<EventVenue>().ToList();
            var eventVenues = repository.GetAll<EventVenue>("Event,Venue,TicketTemplate").ToList();
            return eventVenues;
        }

        public EventVenue GetEventVenueById(int id)
        {
            repository = new GenericRepository();
            var eventVenue = repository.GetByKey<EventVenue>(id);
            return eventVenue;
        }

        public void CreateEventVenue(EventVenue eventVenue)
        {
            repository = new GenericRepository();
            try
            {
                repository.UnitOfWork.BeginTransaction();
                repository.Add<EventVenue>(eventVenue);
                repository.UnitOfWork.CommitTransaction();
            }
            catch (Exception)
            {
                if (repository.UnitOfWork.IsInTransaction)
                    repository.UnitOfWork.RollBackTransaction();
                throw;
            }

        }

        public void UpdateEventVenue(EventVenue eventVenue)
        {
            repository = new GenericRepository();
            try
            {
                repository.UnitOfWork.BeginTransaction();
                repository.Update<EventVenue>(eventVenue);
                repository.UnitOfWork.CommitTransaction();
            }
            catch (Exception)
            {
                if (repository.UnitOfWork.IsInTransaction)
                    repository.UnitOfWork.RollBackTransaction();
                throw;
            }
        }

        public void DeleteEventVenue(EventVenue eventVenue)
        {
            repository = new GenericRepository();
            try
            {
                repository.UnitOfWork.BeginTransaction();
                repository.Attach<EventVenue>(eventVenue);
                repository.Delete<EventVenue>(eventVenue);
                repository.UnitOfWork.CommitTransaction();
            }
            catch (Exception)
            {
                if (repository.UnitOfWork.IsInTransaction)
                    repository.UnitOfWork.RollBackTransaction();
                throw;
            }
        }

        public void DeleteEventVenueById(int id)
        {
            repository = new GenericRepository();
            try
            {
                repository.UnitOfWork.BeginTransaction();
                repository.Delete<EventVenue>(u => u.Id == id);
                repository.UnitOfWork.CommitTransaction();
            }
            catch (Exception)
            {
                if (repository.UnitOfWork.IsInTransaction)
                    repository.UnitOfWork.RollBackTransaction();
                throw;
            }
        }
        #endregion

        #region Ticket, TicketType, TicketTemplate, TicketQuota
    
        #region Ticket
        public List<Ticket> GetAllTickets()
        {
            repository = new GenericRepository();
            var tickets = repository.GetAll<Ticket>().ToList();
            return tickets;
        }

        public Ticket GetTicketById(int id)
        {
            throw new NotImplementedException();
        }

        public void CreatTicket(Ticket ticket)
        {
            throw new NotImplementedException();
        }

        public void UpdateTicket(Ticket ticket)
        {
            throw new NotImplementedException();
        }

        public void DeleteTicket(Ticket ticket)
        {
            throw new NotImplementedException();
        }

        public void DeleteTicketById(int id)
        {
            throw new NotImplementedException();
        }
        public List<Ticket> GetAllTicketsByEventIdAndVenueId(int event_id, int venue_id)
        {
            repository = new GenericRepository();
            var tickets = repository.GetAll<Ticket>("AgentBranch,TicketType,TicketType.EventVenue,TicketType.TicketQuotas").Where(ticket => ticket.TicketType.EventVenue.Event_Id == event_id && ticket.TicketType.EventVenue.Venue_Id == venue_id).ToList();
            return tickets;
        }
        public List<Ticket> GetTicketsByAgentBranchNTicketTypeNQty(int agentBranchId, int ticketTypeId, int sellQty)
        {
            repository = new GenericRepository();
            var tickets = repository.GetAll<Ticket>().Where(t => t.TicketType_Id == ticketTypeId && t.AgentBranch_Id == agentBranchId && t.Customer_Id == null).Take(sellQty).ToList();
            return tickets;
        }
        public void SellTickets(int ticketTypeId, int agentBranchId, int customerId, int quantity, int paymentModeId, decimal TotalAmount)
        {
            repository = new GenericRepository();
            try
            {
                repository.UnitOfWork.BeginTransaction();
                var payment = new Payment() { Amount = TotalAmount, Customer_Id = customerId, PaymentMode_Id = paymentModeId, SuccessfulPayment = true };
                repository.Add<Payment>(payment);
                var tickets = repository.GetAll<Ticket>().Where(t => t.TicketType_Id == ticketTypeId && t.AgentBranch_Id == agentBranchId && t.Customer_Id == null).Take(quantity);
                foreach (var ticket in tickets)
                {
                    ticket.Customer_Id = customerId;
                    ticket.Payment = payment;
                    repository.Update<Ticket>(ticket);
                }

                repository.UnitOfWork.CommitTransaction();
            }
            catch (Exception)
            {
                if (repository.UnitOfWork.IsInTransaction)
                {
                    repository.UnitOfWork.RollBackTransaction();
                }
                throw;
            }


        }
        #endregion

        #region TicketType
        public List<TicketType> GetAllTicketTypes()
        {
            repository = new GenericRepository();
            //var ticketTypes = repository.GetAll<TicketType>("EventVenue").ToList();
            var ticketTypes = repository.GetAll<TicketType>(tt => tt.EventVenue).ToList();
            return ticketTypes;
        }

        public TicketType GetTicketTypeById(int id)
        {
            repository = new GenericRepository();
            var ticketType = repository.GetByKey<TicketType>(id);
            return ticketType;
        }

        public void CreatTicketType(TicketType ticketType)
        {
            repository = new GenericRepository();
            try
            {
                repository.UnitOfWork.BeginTransaction();
                repository.Add<TicketType>(ticketType);
                repository.UnitOfWork.CommitTransaction();
            }
            catch (Exception)
            {
                if (repository.UnitOfWork.IsInTransaction)
                    repository.UnitOfWork.RollBackTransaction();
                throw;
            }
        }

        public void UpdateTicketType(TicketType ticketType)
        {
            repository = new GenericRepository();
            try
            {
                repository.UnitOfWork.BeginTransaction();
                repository.Update<TicketType>(ticketType);
                repository.UnitOfWork.CommitTransaction();
            }
            catch (Exception)
            {
                if (repository.UnitOfWork.IsInTransaction)
                    repository.UnitOfWork.RollBackTransaction();
                throw;
            }
        }

        public void DeleteTicketType(TicketType ticketType)
        {
            repository = new GenericRepository();
            try
            {
                repository.UnitOfWork.BeginTransaction();
                repository.Attach<TicketType>(ticketType);
                repository.Delete<TicketType>(ticketType);
                repository.UnitOfWork.CommitTransaction();
            }
            catch (Exception)
            {
                if (repository.UnitOfWork.IsInTransaction)
                    repository.UnitOfWork.RollBackTransaction();
                throw;
            }
        }

        public void DeleteTicketTypeById(int id)
        {
            repository = new GenericRepository();
            try
            {
                repository.UnitOfWork.BeginTransaction();
                var venue = repository.GetByKey<TicketType>(id);
                repository.Delete<TicketType>(u => u.Id == id);
                repository.UnitOfWork.CommitTransaction();
            }
            catch (Exception)
            {
                if (repository.UnitOfWork.IsInTransaction)
                    repository.UnitOfWork.RollBackTransaction();
                throw;
            }
        }
        public List<TicketType> GetAllTicketTypesWithEventVenue()
        {
            repository = new GenericRepository();
            var ticketTypes = repository.GetAll<TicketType>("EventVenue").ToList();
            return ticketTypes;
        }
        #endregion
        
        #region TicketTemplate
        public List<TicketTemplate> GetAllTicketTemplates()
        {
            repository = new GenericRepository();
            var tikcetTemplates = repository.GetAll<TicketTemplate>().ToList();
            return tikcetTemplates;
        }

        public TicketTemplate GetTicketTemplateById(int id)
        {
            repository = new GenericRepository();
            var ticketTemplate = repository.GetByKey<TicketTemplate>(id);
            return ticketTemplate;
        }

        public void CreatTicketTemplate(TicketTemplate ticketTemplate)
        {
            repository = new GenericRepository();
            try
            {
                repository.UnitOfWork.BeginTransaction();
                repository.Add<TicketTemplate>(ticketTemplate);
                repository.UnitOfWork.CommitTransaction();
            }
            catch (Exception)
            {
                if (repository.UnitOfWork.IsInTransaction)
                    repository.UnitOfWork.RollBackTransaction();
                throw;
            }
        }

        public void UpdateTicketTemplate(TicketTemplate ticketTemplate)
        {
            repository = new GenericRepository();
            try
            {
                repository.UnitOfWork.BeginTransaction();
                repository.Update<TicketTemplate>(ticketTemplate);
                repository.UnitOfWork.CommitTransaction();
            }
            catch (Exception)
            {
                if (repository.UnitOfWork.IsInTransaction)
                    repository.UnitOfWork.RollBackTransaction();
                throw;
            }
        }

        public void DeleteTicketTemplate(TicketTemplate ticketTemplate)
        {
            repository = new GenericRepository();
            try
            {
                repository.UnitOfWork.BeginTransaction();
                repository.Attach<TicketTemplate>(ticketTemplate);
                repository.Delete<TicketTemplate>(ticketTemplate);
                repository.UnitOfWork.CommitTransaction();
            }
            catch (Exception)
            {
                if (repository.UnitOfWork.IsInTransaction)
                    repository.UnitOfWork.RollBackTransaction();
                throw;
            }
        }

        public void DeleteTicketTemplateById(int id)
        {
            repository = new GenericRepository();
            try
            {
                repository.UnitOfWork.BeginTransaction();
                repository.Delete<TicketTemplate>(u => u.Id == id);
                repository.UnitOfWork.CommitTransaction();
            }
            catch (Exception)
            {
                if (repository.UnitOfWork.IsInTransaction)
                    repository.UnitOfWork.RollBackTransaction();
                throw;
            }
        }

        #endregion
        
        #region TicketQuota
        public List<TicketQuota> GetAllTicketQuotas()
        {
            repository = new GenericRepository();
            var ticketQuotas = repository.GetAll<TicketQuota>("TicketType,TicketType.EventVenue,AgentBranch").ToList();
            return ticketQuotas;
        }

        public TicketQuota GetTicketQuotaById(int id)
        {
            repository = new GenericRepository();
            var ticketQuota = repository.GetByKey<TicketQuota>(id);
            return ticketQuota;
        }
        public TicketQuota GetTicketQuotaLoadedById(int id)
        {
            repository = new GenericRepository();
            var ticketQuota = repository.GetAll<TicketQuota>("TicketType,TicketType.EventVenue,AgentBranch").Where(quota => quota.Id == id).FirstOrDefault();
            return ticketQuota;
        }


        public void CreatTicketQuota(TicketQuota ticketQuota)
        {
            repository = new GenericRepository();

            try
            {
                repository.UnitOfWork.BeginTransaction();
                repository.Add<TicketQuota>(ticketQuota);

                DateTime showDateTime = repository.GetAll<TicketType>("EventVenue").Where(tt => tt.Id == ticketQuota.TicketType_Id).Select(tt => tt.EventVenue.ShowDateTime).FirstOrDefault();

                for (int i = 0; i < ticketQuota.QuotaQuantity; i++)
                {
                    var ticket = new Ticket() { AgentBranch_Id = ticketQuota.AgentBranch_Id, TicketType_Id = ticketQuota.TicketType_Id, EventDate = showDateTime, ElectornicTicketNumber = Guid.NewGuid() };
                    repository.Add<Ticket>(ticket);
                }
                repository.UnitOfWork.CommitTransaction();
            }
            catch (Exception)
            {
                if (repository.UnitOfWork.IsInTransaction)
                    repository.UnitOfWork.RollBackTransaction();
                throw;
            }
        }


        public void UpdateTicketQuota(TicketQuota ticketQuota)
        {
            repository = new GenericRepository();
            try
            {
                repository.UnitOfWork.BeginTransaction();
                int oldQty = repository.GetByKey<TicketQuota>(ticketQuota.Id).QuotaQuantity;
                int newQty = ticketQuota.QuotaQuantity;

                if (newQty > oldQty)
                {
                    DateTime showDateTime = repository.GetAll<TicketType>("EventVenue").Where(tt => tt.Id == ticketQuota.TicketType_Id).Select(tt => tt.EventVenue.ShowDateTime).FirstOrDefault();
                    for (int i = 0; i < newQty - oldQty; i++)
                    {
                        //Add new tickets
                        var ticket = new Ticket() { AgentBranch_Id = ticketQuota.AgentBranch_Id, TicketType_Id = ticketQuota.TicketType_Id, EventDate = showDateTime, ElectornicTicketNumber = Guid.NewGuid() };
                        repository.Add<Ticket>(ticket);
                    }
                }
                else if (newQty < oldQty)
                {
                    //Delete some tickets
                    var ticketsThatCanBeDeleted = repository.GetAll<Ticket>().Where(t => t.TicketType_Id == ticketQuota.TicketType_Id && t.AgentBranch_Id == ticketQuota.AgentBranch_Id && t.Customer_Id == null && t.PhysicalTicketNumber == null);
                    int noOfTcketsToBeDeleted = oldQty - newQty;
                    if (ticketsThatCanBeDeleted.Count() >= noOfTcketsToBeDeleted)
                    {
                        int i = 1;
                        foreach (var item in ticketsThatCanBeDeleted)
                        {
                            if (i++ <= noOfTcketsToBeDeleted)
                            {
                                repository.Delete<Ticket>(item);
                            }

                            else
                            {
                                break;
                            }
                        }

                    }
                    else
                    {
                        throw new Exception("Can not update with the quota value because more tickets have been sold than the new quota value.");
                    }
                }

                repository.Update<TicketQuota>(ticketQuota);
                repository.UnitOfWork.CommitTransaction();
            }
            catch (Exception)
            {
                if (repository.UnitOfWork.IsInTransaction)
                    repository.UnitOfWork.RollBackTransaction();
                throw;
            }
        }

        public void DeleteTicketQuota(TicketQuota ticketQuota)
        {
            repository = new GenericRepository();
            try
            {
                repository.UnitOfWork.BeginTransaction();

                var ticketsThatCanNotBeDeleted = repository.GetAll<Ticket>().Where(t => t.TicketType_Id == ticketQuota.TicketType_Id && t.AgentBranch_Id == ticketQuota.AgentBranch_Id && (t.Customer_Id != null || t.PhysicalTicketNumber != null));
                if (ticketsThatCanNotBeDeleted.Count() > 0)
                {

                    throw new Exception("Can not delete the quota because some tikcets has been sold.");
                }
                else
                {
                    repository.Delete<Ticket>(t => t.TicketType_Id == ticketQuota.TicketType_Id && t.AgentBranch_Id == ticketQuota.AgentBranch_Id);
                    repository.Attach<TicketQuota>(ticketQuota);
                    repository.Delete<TicketQuota>(ticketQuota);
                    repository.UnitOfWork.CommitTransaction();
                }
            }
            catch (Exception)
            {
                if (repository.UnitOfWork.IsInTransaction)
                    repository.UnitOfWork.RollBackTransaction();
                throw;
            }
        }

        public void DeleteTicketQuotaById(int id)
        {
            repository = new GenericRepository();
            try
            {
                repository.UnitOfWork.BeginTransaction();
                var ticketQuota = repository.GetByKey<TicketQuota>(id);
                var ticketsThatCanNotBeDeleted = repository.GetAll<Ticket>().Where(t => t.TicketType_Id == ticketQuota.TicketType_Id && t.AgentBranch_Id == ticketQuota.AgentBranch_Id && (t.Customer_Id != null || t.PhysicalTicketNumber != null));
                if (ticketsThatCanNotBeDeleted.Count() > 0)
                {

                    throw new Exception("Can not delete the quota because some tikcets has been sold.");
                }
                else
                {
                    repository.Delete<Ticket>(t => t.TicketType_Id == ticketQuota.TicketType_Id && t.AgentBranch_Id == ticketQuota.AgentBranch_Id);
                    repository.Delete<TicketQuota>(u => u.Id == id);
                    repository.UnitOfWork.CommitTransaction();
                }
            }
            catch (Exception)
            {
                if (repository.UnitOfWork.IsInTransaction)
                    repository.UnitOfWork.RollBackTransaction();
                throw;
            }
        }
        #endregion
        #endregion

        #region Payment
        public List<Payment> GetAllPayments()
        {
            throw new NotImplementedException();
        }

        public Payment GetPaymentById(int id)
        {
            throw new NotImplementedException();
        }

        public void CreatePayment(Payment payment)
        {
            throw new NotImplementedException();
        }

        public void UpdatePayment(Payment payment)
        {
            throw new NotImplementedException();
        }

        public void DeletePayment(Payment payment)
        {
            throw new NotImplementedException();
        }

        public void DeletePaymemntById(int id)
        {
            throw new NotImplementedException();
        }
        public List<PaymentMode> GetAllPaymentModes()
        {
            repository = new GenericRepository();
            var paymentModes = repository.GetAll<PaymentMode>().ToList();
            return paymentModes;
        }

        #endregion


        #region City
        
        public List<City> FindCities(string searchText, int maxResults)
        {
            repository = new GenericRepository();
            var cities = repository.GetAll<City>().Where(city => city.CityName.ToLower().Contains(searchText.ToLower())).Take(maxResults).ToList();
            return cities;
        }
        #endregion
    }
}
